package com.docmgmt.mvp.ragflow.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * AI 问答请求 DTO
 * 
 * 用于调用 RAGFlow 的 POST /api/v1/chats/{chat_id}/completions 接口
 * 
 * 使用示例：
 * <pre>
 * CompletionRequest request = CompletionRequest.builder()
 *     .question("什么是 RAGFlow？")
 *     .sessionId("session_xxx")  // 可选，不传则创建新会话
 *     .stream(false)             // 可选，默认 false
 *     .build();
 * </pre>
 * 
 * @author Dora
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CompletionRequest {

    /**
     * 用户问题（必填）
     * 
     * 这是用户向 AI 助手提出的问题或指令。
     * 
     * 限制：
     * - 不能为空或纯空格
     * - 长度范围：1-10000 字符
     * - 支持多行文本
     * 
     * 示例：
     * - "什么是 RAGFlow？"
     * - "请总结这份文档的主要内容"
     * - "帮我分析一下这个数据的趋势"
     */
    @NotBlank(message = "问题内容不能为空")
    @Size(min = 1, max = 10000, message = "问题长度必须在 1-10000 字符之间")
    private String question;

    /**
     * 会话 ID（可选）
     * 
     * 用于标识一个对话会话，实现多轮对话的上下文关联。
     * 
     * 行为：
     * - 如果传值：将问题添加到指定会话，AI 会参考该会话的历史对话
     * - 如果不传：自动创建新会话，开始全新的对话
     * 
     * 格式要求：
     * - 32 位十六进制字符串（UUID 格式）
     * - 示例：session_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
     * 
     * 注意事项：
     * - 会话 ID 必须属于当前用户
     * - 会话 ID 必须关联到当前 Chat Assistant
     * - 无效的会话 ID 会导致 404 错误
     */
    @JsonProperty("session_id")
    @Pattern(
        regexp = "^[a-zA-Z0-9_-]{1,64}$",
        message = "会话 ID 格式不正确，应为 1-64 位字母数字下划线或连字符"
    )
    private String sessionId;

    /**
     * 是否使用流式返回（可选）
     * 
     * 控制 AI 回答的返回方式：
     * 
     * 【非流式返回（stream = false，默认）】
     * - 等待 AI 生成完整答案后一次性返回
     * - 使用标准 HTTP POST 请求
     * - 返回格式：JSON 对象
     * - 适用场景：
     *   * 短文本问答
     *   * 网络不稳定的环境
     *   * 需要完整答案后再处理的场景
     * 
     * 【流式返回（stream = true）】
     * - AI 生成答案的同时逐字/逐句返回
     * - 使用 Server-Sent Events (SSE) 协议
     * - 返回格式：事件流（text/event-stream）
     * - 适用场景：
     *   * 长文本回答（提升用户体验）
     *   * 实时交互场景
     *   * 类似 ChatGPT 的打字机效果
     * 
     * 技术实现：
     * - 后端：Spring WebFlux 的 Flux<ServerSentEvent>
     * - 前端：EventSource API 或 fetch() with ReadableStream
     * 
     * 默认值：false
     * 
     * 示例：
     * <pre>
     * // 非流式返回
     * CompletionRequest request = CompletionRequest.builder()
     *     .question("什么是 RAGFlow？")
     *     .stream(false)
     *     .build();
     * 
     * // 流式返回
     * CompletionRequest request = CompletionRequest.builder()
     *     .question("请详细介绍 RAGFlow 的架构设计")
     *     .stream(true)
     *     .build();
     * </pre>
     */
    @Builder.Default
    private Boolean stream = false;

    /**
     * 文档过滤列表（可选）
     *
     * 用于限制 AI 问答的文档范围，实现文件级权限控制。
     *
     * 工作原理：
     * - 传递用户有权限访问的文档 ID 列表
     * - RAGFlow 只从这些文档中检索答案
     * - 未列出的文档不会被查询
     *
     * 格式：
     * - 逗号分隔的文档 ID 字符串
     * - 每个文档 ID 为 32 位十六进制字符串
     * - 示例："5d7a5c72b98011f092cf326df6453d50,350f71deb97e11f0b665326df6453d50"
     *
     * 使用场景：
     * - 用户只能访问部分文件夹的文件
     * - 需要实现细粒度的权限控制
     * - 跨部门知识库查询（只查询有权限的文档）
     *
     * 性能建议：
     * - 文档数量 < 100：性能良好
     * - 文档数量 100-500：可接受
     * - 文档数量 > 500：考虑分批查询或优化权限设计
     *
     * 注意事项：
     * - 如果不传此参数，查询所有知识库中的文档
     * - 传递空字符串或空列表，不会返回任何结果
     * - 文档 ID 必须是 RAGFlow 返回的 32 位十六进制字符串
     *
     * 技术实现：
     * - RAGFlow API 参数名：doc_ids
     * - 支持动态传递文件列表
     * - 底层使用 Elasticsearch 过滤
     *
     * 示例：
     * <pre>
     * // 方式 1：直接设置逗号分隔字符串
     * CompletionRequest request = CompletionRequest.builder()
     *     .question("RAGFlow的主要功能有哪些？")
     *     .docIds("5d7a5c72b98011f092cf326df6453d50,350f71deb97e11f0b665326df6453d50")
     *     .build();
     *
     * // 方式 2：从列表构建
     * List&lt;String&gt; accessibleDocIds = fileService.getAccessibleDocIds(userId);
     * String docIds = CompletionRequest.buildDocIds(accessibleDocIds);
     * CompletionRequest request = CompletionRequest.builder()
     *     .question("RAGFlow的主要功能有哪些？")
     *     .docIds(docIds)
     *     .build();
     * </pre>
     */
    @JsonProperty("doc_ids")
    @Pattern(
        regexp = "^([a-f0-9]{32})(,[a-f0-9]{32})*$",
        message = "doc_ids 格式不正确，应为逗号分隔的32位十六进制字符串"
    )
    private String docIds;

    /**
     * 获取流式返回标志（非空安全）
     *
     * 如果 stream 字段为 null，返回默认值 false
     *
     * @return 是否使用流式返回
     */
    public boolean isStream() {
        return stream != null && stream;
    }

    /**
     * 从文档 ID 列表构建 doc_ids 字符串
     *
     * 将 List&lt;String&gt; 转换为逗号分隔的字符串，用于传递给 RAGFlow API。
     *
     * 使用场景：
     * - 从数据库查询用户有权限的文档 ID 列表
     * - 需要动态构建 doc_ids 参数
     *
     * 示例：
     * <pre>
     * List&lt;String&gt; docIdList = Arrays.asList(
     *     "5d7a5c72b98011f092cf326df6453d50",
     *     "350f71deb97e11f0b665326df6453d50"
     * );
     * String docIds = CompletionRequest.buildDocIds(docIdList);
     * // 结果："5d7a5c72b98011f092cf326df6453d50,350f71deb97e11f0b665326df6453d50"
     * </pre>
     *
     * @param docIdList 文档 ID 列表
     * @return 逗号分隔的字符串，如果列表为空或 null 则返回 null
     */
    public static String buildDocIds(List<String> docIdList) {
        if (docIdList == null || docIdList.isEmpty()) {
            return null;
        }
        return String.join(",", docIdList);
    }

    /**
     * 解析 doc_ids 字符串为列表
     *
     * 将逗号分隔的字符串转换为 List&lt;String&gt;，便于后续处理。
     *
     * 使用场景：
     * - 需要遍历文档 ID
     * - 需要统计文档数量
     * - 需要验证文档 ID 格式
     *
     * 示例：
     * <pre>
     * CompletionRequest request = CompletionRequest.builder()
     *     .docIds("5d7a5c72b98011f092cf326df6453d50,350f71deb97e11f0b665326df6453d50")
     *     .build();
     *
     * List&lt;String&gt; docIdList = request.parseDocIds();
     * // 结果：["5d7a5c72b98011f092cf326df6453d50", "350f71deb97e11f0b665326df6453d50"]
     * </pre>
     *
     * @return 文档 ID 列表，如果 docIds 为空或 null 则返回空列表
     */
    public List<String> parseDocIds() {
        if (docIds == null || docIds.trim().isEmpty()) {
            return Collections.emptyList();
        }
        return Arrays.asList(docIds.split(","));
    }

    /**
     * 获取文档数量
     *
     * 统计 doc_ids 参数中包含的文档数量。
     *
     * 使用场景：
     * - 性能监控（记录每次查询的文档数量）
     * - 权限验证（检查文档数量是否合理）
     * - 日志记录（记录查询范围）
     *
     * 示例：
     * <pre>
     * CompletionRequest request = CompletionRequest.builder()
     *     .docIds("5d7a5c72b98011f092cf326df6453d50,350f71deb97e11f0b665326df6453d50")
     *     .build();
     *
     * int count = request.getDocCount();
     * // 结果：2
     *
     * if (count > 100) {
     *     log.warn("文档过滤列表过大({}个)，可能影响性能", count);
     * }
     * </pre>
     *
     * @return 文档数量，如果 docIds 为空或 null 则返回 0
     */
    public int getDocCount() {
        return parseDocIds().size();
    }
}

